# -*- coding: utf-8 -*-
import re
import os
import time
import datetime
import uiautomation as uia
import pyperclip
import LXWindowUtil

# 唤醒微信窗口（确保微信已登录）
# uia.SendKeys(text='{Alt}{Ctrl}w')  # 快捷键唤醒微信

# 定位微信主窗口
wx_window = uia.WindowControl(Name="微信", ClassName="WeChatMainWndForPC")
if not wx_window.Exists():
    LXWindowUtil.OpenWindow(classname="WeChatMainWndForPC")
    wx_window = uia.WindowControl(Name="微信", ClassName="WeChatMainWndForPC")
    if not wx_window.Exists():
        raise Exception("微信窗口未找到！")
wx_window.SetTopmost(False)  # 窗口不置顶 会有其他问题

# 获取窗口控件
MainControl1 = [i for i in wx_window.GetChildren() if not i.ClassName][0]
MainControl2 = MainControl1.GetFirstChildControl()
NavigationBox, SessionBox, ChatBox  = MainControl2.GetChildren()

# 消息列表
C_MsgList = ChatBox.ListControl(Name='消息')

# 聊天框
A_ChatIcon = NavigationBox.ButtonControl(Name='聊天')

# 自己的头像框
A_MyIcon = NavigationBox.ButtonControl()
nickname = A_MyIcon.Name
print(f'当前登录用户：{nickname}')

def GetSessionList():
    return {}


# 关闭窗口
def Close():
    wx_window.GetWindowPattern().Close()

def GetSessionAmont(SessionItem):
    matchobj = re.search('\d+条新消息', SessionItem.Name)
    amount = 0
    if matchobj:
        try:
            amount = int([i for i in SessionItem.GetFirstChildControl().GetChildren() if type(i) == uia.TextControl][0].Name)
        except:
            pass
    sessionname = SessionItem.Name if SessionItem.ButtonControl().Name == 'SessionListItem' else SessionItem.ButtonControl().Name
    return sessionname, amount
    
def GetSessionList(newmessage=False):
    SessionItem = SessionBox.ListItemControl()
    SessionItemList = []
    SessionList = {}
    for i in range(100):
        if SessionItem.BoundingRectangle.width() != 0:
            try:
                sessionname = SessionItem.Name if SessionItem.ButtonControl().Name == 'SessionListItem' else SessionItem.ButtonControl().Name
                name, amount = GetSessionAmont(SessionItem)
            except:
                break
            if name not in SessionItemList:
                SessionItemList.append(name)
            if name not in SessionList:
                SessionList[name] = amount
        SessionItem = SessionItem.GetNextSiblingControl()
        if not SessionItem:
            break
        
    if newmessage:
        return {i:SessionList[i] for i in SessionList if SessionList[i] > 0}
    return SessionList

# 查找目标用户窗口
def QueryChat(who, timeout=2):
    SessionItem = SessionBox.ListItemControl()
    for i in range(100):
        # 循环判断最近100个聊天用户是否包含目标用户
        if SessionItem.BoundingRectangle.width() != 0:
            try:
                sessionname = SessionItem.Name if SessionItem.ButtonControl().Name == 'SessionListItem' else SessionItem.ButtonControl().Name
                # print(f'搜索结果：{sessionname}')
                if sessionname == who:
                   print('最近100条里包含目标用户')
                   return who
            except:
                break
        SessionItem = SessionItem.GetNextSiblingControl() # 获取下一个聊天用户
        if not SessionItem:
            break

    # 未找到目标用户，打开搜索框并搜索目标用户
    wx_window.SendKeys('{Ctrl}f', waitTime=0.5)  # 打开搜索框
    wx_window.SendKeys('{Ctrl}a', waitTime=0.2)  # 清空搜索框
    wx_window.SendKey(uia.SpecialKeyNames['DELETE'], waitTime=0.2)
    pyperclip.copy(who) # 拷贝到剪切板
    wx_window.EditControl(Name="搜索").SendKeys('{Ctrl}v', waitTime=0.5) # 粘贴搜索内容
    # wx_window.SendKey(uia.SpecialKeyNames['ENTER'], waitTime=0.5)  # 进入群聊
    target_control = SessionBox.TextControl(Name=f"<em>{who}</em>")
    if target_control.Exists(timeout):
        print('选择完全匹配项')
        target_control.Click(simulateMove=False)
        return who
    else:
        search_result_control = SessionBox.GetChildren()[1].GetChildren()[1].GetFirstChildControl()
        if not search_result_control.PaneControl(searchDepth=1).TextControl(RegexName='联系人|群聊').Exists(0.1):
            print(f'未找到搜索结果: {who}')
            A_ChatIcon.Click(simulateMove=False) # 关闭搜索框
            return False
        print('选择搜索结果第一个')
        target_control = search_result_control.Control(RegexName=f'.*{who}.*')
        chatname = target_control.Name
        target_control.Click(simulateMove=False)
        return chatname

# 选择聊天窗口
def SelectChat(who):
    LXWindowUtil.OpenWindow(classname="WeChatMainWndForPC") # 打开微信窗口
    # 判断是否已打开聊天窗口
    exists = uia.WindowControl(searchDepth=1, ClassName='ChatWnd', Name=who).Exists(maxSearchSeconds=0.1)
    if not exists:
        print(f'未找到已打开的会话窗口 {who}')
        select = QueryChat(who)
        # print(f'搜索结果：{select}')
        if(select == who): 
            # 双击打开会话窗口
            SessionBox.ListItemControl(RegexName=who, timeout=3).DoubleClick(simulateMove=False)
        else:
            print(f'未搜索到该用户 {who}')
            return False
    return True
# SelectChat('🍀游林夕🍀')
DEFALUT_SAVEPATH = os.path.join(os.getcwd(), 'wxauto文件')

def SaveImg(savepath='', timeout=10):
    if not savepath:
        savepath = os.path.join(DEFALUT_SAVEPATH, f"微信图片_{datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')}.jpg")
    if not os.path.exists(os.path.split(savepath)[0]):
        os.makedirs(os.path.split(savepath)[0])
    
    api = uia.WindowControl(ClassName='ImagePreviewWnd', searchDepth=1)
    MainControl1 = [i for i in api.GetChildren() if not i.ClassName][0]
    ToolsBox, PhotoBox = MainControl1.GetChildren()

    t_zoom = ToolsBox.ButtonControl(Name='放大')
    t_save = ToolsBox.ButtonControl(Name='另存为...')
    if t_zoom.Exists(maxSearchSeconds=5):
        t_save.Click(simulateMove=False, waitTime=1)
    else:
        raise TimeoutError('下载超时')
    handle = LXWindowUtil.FindWindow(name='另存为...')
    if handle:
        LXWindowUtil.EnterWindow(handle)
    api.SendKeys('{Esc}')
    return savepath
        

def _download_pic(msgitem,C_MsgList):
    imgcontrol = msgitem.ButtonControl(Name='')
    if not imgcontrol.Exists(0.5):
        return None
    LXWindowUtil.RollIntoView(C_MsgList, imgcontrol)
    imgcontrol.Click(simulateMove=False)
    return  SaveImg()

SYS_TEXT_HEIGHT = 33
TIME_TEXT_HEIGHT = 34
RECALL_TEXT_HEIGHT = 45
CHAT_TEXT_HEIGHT = 52
CHAT_IMG_HEIGHT = 117

def GetMsg(MsgItem):
    uia.SetGlobalSearchTimeout(0)
    MsgItemName = MsgItem.Name
    id = ''.join([str(i) for i in MsgItem.GetRuntimeId()])
    Msg =  {'type':'friend','content':MsgItemName, 'id':id,'control':MsgItem}
    if MsgItem.BoundingRectangle.height() == SYS_TEXT_HEIGHT:
        Msg['type'] = 'sys'
    elif MsgItem.BoundingRectangle.height() == TIME_TEXT_HEIGHT:
        Msg['type'] = 'time'
    elif MsgItem.BoundingRectangle.height() == RECALL_TEXT_HEIGHT:
        if '撤回' in MsgItemName:
            Msg['type'] = 'recall'
    else:
        Index = 1
        User = MsgItem.ButtonControl(foundIndex=Index)
        try:
            while True:
                if User.Name == '':
                    Index += 1
                    User = MsgItem.ButtonControl(foundIndex=Index)
                else:
                    break
            winrect = MsgItem.BoundingRectangle
            mid = (winrect.left + winrect.right)/2
            Msg['sender']= User.Name
            if User.BoundingRectangle.left < mid:
                if MsgItem.TextControl().Exists(0.1) and MsgItem.TextControl().BoundingRectangle.top < User.BoundingRectangle.top:
                    Msg['remark']= MsgItem.TextControl().Name
            else:
                Msg['type'] = 'self'
        except:
            Msg['type'] = 'sys'
    uia.SetGlobalSearchTimeout(10.0)
    return Msg

# 最后聊天一次时间
lastMsgids={}

# 获取聊天记录
def GetMsgs(who, savepic=False, savefile=False, savevoice=False):
    MsgList = uia.WindowControl(searchDepth=1, ClassName='ChatWnd', Name=who)
    if not MsgList.Exists(maxSearchSeconds=0.1):
        print(f'未找到已打开的会话窗口 {who}')
        if not SelectChat(who):
            return []
    
    C_MsgList = MsgList.ListControl()
    msgitems = C_MsgList.GetChildren()
    msgs = []
    if who in lastMsgids:
        for MsgItem in reversed(msgitems):
            if MsgItem.ControlTypeName == 'ListItemControl':
                if MsgItem.GetRuntimeId() <= lastMsgids[who]: # 已经获取过的消息
                    break
                msg = GetMsg(MsgItem)
                if msg['content'] == "[图片]":
                    #打开聊天窗口
                    LXWindowUtil.OpenWindow(classname="ChatWnd",name=who)
                    path = _download_pic(MsgItem,C_MsgList)
                    msg['type'] = 'img'
                    msg['path'] = path
                msgs.append(msg)
    lastMsgids[who] = msgitems[-1].GetRuntimeId() # 获取最后一条消息的id
    return reversed(msgs)

def SendMsg(who, msg, at=None):
    MsgList = uia.WindowControl(searchDepth=1, ClassName='ChatWnd', Name=who)
    if not MsgList.Exists(maxSearchSeconds=0.1):
        print(f'未找到已打开的会话窗口 {who}')
        if not SelectChat(who):
            return False
    editbox=MsgList.EditControl()
    if not editbox.HasKeyboardFocus:
        editbox.Click(simulateMove=False)
    if at:
        if isinstance(at, str):
            at = [at]
        for i in at:
            editbox.SendKeys('@'+i)
            atwnd = MsgList.PaneControl(ClassName='ChatContactMenu')
            if atwnd.Exists(maxSearchSeconds=0.1):
                atwnd.SendKeys('{ENTER}')
                if msg and not msg.startswith('\n'):
                    msg = '\n' + msg

    t0 = time.time()
    while True:
        if time.time() - t0 > 10:
            raise TimeoutError(f'发送消息超时 --> {who} - {msg}')
        pyperclip.copy(msg)
        editbox.SendKeys('{Ctrl}v')
        if editbox.GetValuePattern().Value:
            break
    editbox.SendKeys('{Enter}')

import uuid

def msgBot(who):
    msgs = GetMsgs(who)
    for msg in msgs:
        if msg['type'] == 'sys':  # 修改为字典键访问方式
            print(f'【系统消息】{msg["content"]}')
        
        elif msg['type'] == 'friend':
            # 这里需要确认 'sender' 键是否存在
            sender = msg.get('sender', '未知发送者') 
            print(f'<{sender.center(10, "-")}>：{msg["content"]}')
            
            # ！！！ 回复收到，此处为`chat`而不是`wx` ！！！
            SendMsg(who,f'{msg["content"]}:{uuid.uuid1()}')  
            # 此处将msg.content传递给大模型，再由大模型返回的消息回复即可实现ai聊天
        elif msg['type'] == 'img':
            sender = msg.get('sender', '未知发送者') 
            print(f'<{sender.center(10, "-")}>：{msg["path"]}')
        elif msg['type'] == 'self':
            # 这里需要确认 'sender' 键是否存在
            sender = msg.get('sender', '自己') 
            print(f'<{sender.center(10, "-")}>：{msg["content"]}')
        
        elif msg['type'] == 'time':
            print(f'\n【时间消息】{msg["content"]}')

        elif msg['type'] == 'recall':
            print(f'【撤回消息】{msg["content"]}')

wait = 3  # 设置3秒查看一次是否新消息
while True:
    try:
        msgBot("🍀游林夕🍀")
        msgBot("llt")
        time.sleep(wait)
    except KeyboardInterrupt:
        print('Bye~')
        break
